home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-23 | 14.7 KB | 230 lines | [TEXT/ALFA] |
-
- LESSON 3 "Using variables, constants and memory"
- --------------------------------------------------------------------------------
-
- Contents of this lesson:
-
- 1. VARIABLE, CONSTANT and CREATE
- 2. Strings
- 3. Word summary
- 4. Exercises
-
- ================================================================================
-
- Forth variables, constants and memory is the subject of this lesson.
- Here one learns how to preserve values and how to create simple data
- structures in memory.
-
-
-
- VARIABLE, CONSTANT and CREATE
- -----------------------------
-
- As a Forth program is compiled it builds its dictionary. User defined
- colon definitions go in the dictionary, as do places to store data.
- Forth provides two special purpose words for creating named variables
- and constants and one general purpose word for reserving dictionary
- space.
-
-
- VARIABLE
- --------
-
- We know that a value can be pulled off the data stack and placed on
- the return stack for temporary storage, but how to we preserve a value
- indefinitely? For that Forth provides the word VARIABLE. VARIABLE
- takes the next token in the input stream and creates a special
- dictionary entry with that name. VARIABLE also reserves memory for
- one stack entry (either 16 or 32 bits) and compiles code to push the
- address of this location on the stack when executed. In some Forth
- versions VARIABLE needs a value on the stack to initialize the
- variable. MacQForth does not need a value on the stack and the
- contents of a variable must be initialize by hand (as is the case in
- most programming languages).
-
- E.g.
-
- variable age ( create a variable called 'age' )
-
- 28 age ! ( ! expects a value and an address, it then places that )
- ( value in that address )
-
- age @ . ( @ expects an address and gets the value at that address )
- ( placing it on the stack )
-
-
- There are several things to note in this simple example:
-
- (1) VARIABLE creates a dictionary entry, like : , so it cannot
- be used from within a definition.
- (2) A variable pushes its _address_ in memory on the stack when
- referenced. This is contrary to most programming languages
- which return the variable's _value_ when referenced. Some
- Forths include a type VALUE that acts in this way.
- (3) The words ! and @ deal with 16- or 32-bit words (depending on
- whether the Forth is a 16-bit or 32-bit Forth). So, if the
- variable AGE is at location 16543, then the next 8-bits of
- AGE's value are at location 16544. Unlike C, adding 1 to a
- pointer (an address) in Forth simply adds 1 to the address.
-
- Generally, beginning Forth programmers are discouraged from using too
- many variables. This is because some consider it a matter of skill
- to use as few as possible, but also because all variables are global
- in Forth, i.e. once defined any word defined after the variable can use
- it. This can lead to some frustrating bugs if too many are used.
-
- What if I want to access individual bytes?
-
- Then use C@ and C! in place of @ and ! . Naturally, if one attempts
- to store a number greater than 255 in a single byte only the lower
- 8-bits of the value will be stored.
-
- To review:
-
- Memory access in Forth uses the words @, !, C@, and C! with stack
- effects:
-
- @ ( addr -- value ) return the 16 or 32-bit value at address
- ! ( value addr -- ) store value (16 or 32-bits) at address
- C@ ( addr -- value ) return the byte value (8-bits) at address
- C! ( value addr -- ) store value (<256) at the address
-
- So,
-
- ( assuming a 32-bit Forth )
-
- variable TEXT ( reserve 4 bytes of dictionary named TEXT )
-
- 65 TEXT C! 66 TEXT 1+ C! 67 TEXT 2+ C! 68 TEXT 3 + C!
-
- ( the words 1+ and 2+ add one and two to the top stack value )
-
- Now, what does this do?
-
- Creating the variable reserves 4 bytes of dictionary space, so there
- we have room for 4 8-bit characters:
-
-
- +-- a byte
- V
- +---+---+---+---+
- dictionary -> | 0 | 1 | 2 | 3 |
- +---+---+---+---+
- ^
- address -> 16543 (start of TEXT)
-
-
- The first byte of TEXT is at the address: 16543 = TEXT
- The second byte is at the address : 16544 = TEXT 1+
- The third byte is at address : 16545 = TEXT 2+
- The last (fourth) byte is at address : 16546 = TEXT 3 +
-
- Knowing that ASCII 65 = 'A' we can see that the above puts the
- characters 'ABCD' in the variable TEXT. Normally, one uses variables
- to hold numbers and CREATE to make strings.
-
-
- CONSTANT
- --------
-
- Sometimes the same value is needed repeatedly within a program. In
- such a case it is likely best to use a CONSTANT. CONSTANT works in
- much the same way as VARIABLE: it takes the next token from the input
- stream and creates a dictionary entry with that name. It also takes
- the top stack value and places it in the entry along with code to push
- that value on the stack when executed,
-
- 28 constant AGE ( create a constant called AGE )
-
- AGE ( pushes 28 on the stack )
-
- AGE @ ( fetches the contents of location 28, normally this )
- ( is only useful if the constant corresponds to a )
- ( meaningful memory location, like a hardware address )
-
- On occassion one will see something like:
-
- 0 constant 0
- 1 constant 1
-
- While at first glance this seems rather a waste, it is done to improve
- speed. Recall that when the interpreter/compiler encounters a token
- in the input stream it first attempts to look the token up in the dictionary
- and then if that fails it attempts to convert the token to a number.
- So, since 0 and 1 are frequently used it is slightly faster to define
- them to be a constant so that they are found in the dictionary before
- being converted to a number.
-
- Always remember that freedom to the programmer is the cry of Forth.
- Therefore, Forth allows the following while other languages do not:
-
- 24 3 + .
- 27
-
- 1 constant 3
-
- 24 3 + .
- 25
-
- Yes, Forth will let you redefine a constant! Only the oldest of FORTRAN
- compilers allowed that as far as I know. Note, MacQForth does not
- allow this, though Mops, the Forth MacQForth was written in, does.
-
-
- CREATE
- ------
-
- Create takes the next token from the input stream and defines a
- dictionary entry with that name. That is all it does.
-
- When combined with the word ALLOT to reserve dictionary space CREATE
- becomes quite useful:
-
- create AGES 8 allot
-
- This creates a dictionary entry called AGES and reserves 8 BYTES of
- dictionary space. Note that ALLOT expects the number of _bytes_ to be
- reserved on the stack. Now, suppose we wished to use AGES as an array
- to store the ages of four people, since each age is 16-bits (2 bytes) long
- we need 8 bytes for 4 ages, 4 * 2 = 8. Using the ! and @ words plus
- offsets to the base address AGES as we did with TEXT above we can use
- this section of the dictionary as an array:
-
- : { ( -- ) ; ( a do nothing word )
- : } ( addr index -- addr+index*2 ) 2* + ; ( 2* = 2 * but faster )
-
- 28 AGES { 0 } ! ( put 28 in AGES )
- 27 AGES { 1 } ! ( put 27 in AGES+2 )
- 29 AGES { 2 } ! ( put 29 in AGES+4 )
- 30 AGES { 3 } ! ( put 30 in AGES+6 )
-
- We can recover a value in much the same way:
-
- AGES { 2 } @ . ( outputs 29 )
-
- Now, what is going on here:
-
- (1) CREATE and ALLOT reserved dictionary space and gave it a name.
- (2) } was defined to take an address and index and return the
- desired address. The 2* was necessary since each entry was 2
- bytes in length. In a 32-bit Forth it would have been 4* .
- { was defined to make the code look nicer.
- (3) Note that in true Forth form, there is no such thing as range
- checking. We could have said 33 AGES { 101 } ! and Forth would
- have done it happily. Of course, that part of the dictionary is
- likely to contain data that we do not want changed.
- (4) Negative indices are allowed but not recommended for reason (3)
- above.
- (5) Note that arrays defined in this manner start at index 0, not 1.
-
-
- Other memory access words
- -------------------------
-
- +! ( value addr -- ) add value to the present value in addr
- e.g.
- 3 N ! ( put 3 in N )
- 2 N +! ( leaves 5 in N )
- ( equivalent to N @ 2 + N ! )
-
- , ( value -- ) put